package cooperate

import (
	"sync"

	"gddgame.cc/galaxy/common/namespaces/cooperate/structure"
)

const (
	DefaultKey = ""
)

// 能力来源：科技，天赋，装备，道具
type AbilitySource string

// 能力定义：属性，buff，技能，指令
type AbilityDefine string

type AbilityData interface {
	GetAbilityInstance(mapInstance MapBase, data structure.Data) *AbilityOwner
	GetSourceEffect(dataType structure.PublicDataType, key string, source AbilitySource, define map[int]int) map[structure.PublicDataType]map[string]AbilityEffect
	BaseEffect() AbilityEffect
	FillOwner(instance PropsInstance, owner *AbilityOwner)
}

type AbilityEffect interface {
	GetIds(define AbilityDefine) []int
	GetSlice(define AbilityDefine) []int
	MergeTo(effect AbilityEffect) AbilityEffect
	ChangeSlice(define AbilityDefine, index int, value int)
}

type AbilityOwner struct {
	mutex sync.RWMutex

	needChange bool
	// 由source生成self和targetmap
	Source     map[AbilitySource]map[int]int
	TargetMap  map[structure.PublicDataType]map[string]AbilityEffect
	SelfEffect AbilityEffect

	InheritEffect AbilityEffect
}

func NewAbilityOwner() *AbilityOwner {
	owner := &AbilityOwner{
		Source:     map[AbilitySource]map[int]int{},
		needChange: true,
	}
	return owner
}

func (owner *AbilityOwner) Change() {
	owner.needChange = true
}

func (owner *AbilityOwner) ChangeSource(source AbilitySource, define map[int]int) {
	owner.mutex.Lock()
	owner.Source[source] = define
	owner.mutex.Unlock()
}

func (owner *AbilityOwner) generateSelf(instance PropsInstance, abilityData AbilityData) {
	targetMap := map[structure.PublicDataType]map[string]AbilityEffect{}
	self := abilityData.BaseEffect()
	DataType := instance.GetDataType()
	Key := instance.ToString(Key)
	owner.mutex.RLock()
	for source, define := range owner.Source {
		//fmt.Println(DataType, Key, source, define)
		targetEffect := abilityData.GetSourceEffect(DataType, Key, source, define)
		for dataType, group := range targetEffect {
			allGroup, ok := targetMap[dataType]
			if !ok {
				allGroup = map[string]AbilityEffect{}
				targetMap[dataType] = allGroup
			}
			for key, effect := range group {
				allEffect := allGroup[key]
				allGroup[key] = effect.MergeTo(allEffect)
				if dataType == DataType && (key == Key || key == DefaultKey) {
					self = effect.MergeTo(self)
				}
			}
		}
	}
	owner.mutex.RUnlock()
	owner.TargetMap = targetMap
	owner.SelfEffect = self
}

func (owner *AbilityOwner) generateInherit(mapInstance MapBase, instance PropsInstance, abilityData AbilityData) {
	var effect AbilityEffect
	DataType := instance.GetDataType()
	Key := instance.ToString(Key)
	owner.mutex.RLock()
	for _, data := range instance.Inherits() {
		if data == nil {
			continue
		}
		oo := abilityData.GetAbilityInstance(mapInstance, data)
		if oo != nil {
			if keys, ok := oo.TargetMap[DataType]; ok {
				if valus, ok := keys[Key]; ok {
					effect = valus.MergeTo(effect)
				}
				if valus, ok := keys[DefaultKey]; ok {
					effect = valus.MergeTo(effect)
				}
			}
		}
	}
	owner.mutex.RUnlock()
	owner.InheritEffect = effect
}

func (owner *AbilityOwner) Generate(mapInstance MapBase, instance PropsInstance, abilityData AbilityData) AbilityEffect {
	//fmt.Println("ab own", instance.BaseData(), owner.needChange)
	if owner.needChange {
		owner.needChange = false
		abilityData.FillOwner(instance, owner)
		owner.generateSelf(instance, abilityData)
		owner.generateInherit(mapInstance, instance, abilityData)
		if owner.InheritEffect != nil {
			owner.SelfEffect = owner.InheritEffect.MergeTo(owner.SelfEffect)
		}
	}
	return owner.SelfEffect
}
